package com.lbs.core.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.ImgRaw;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;
import com.lbs.core.shared.parsing.LbsParser;
import com.lbs.core.shared.parsing.LbsParserException;
import com.lbs.core.shared.tables.AbstractData;
import com.lizbet.server.XmlFact;
import com.lizbet.server.XmlRaw;
import com.lizbet.server.myXmlParsingException;


public class FactPdfV3  extends PdfPageEventHelper {

	//Document Data
	public ByteArrayOutputStream dataArray;
	
	//Varidables
	NumberFormat formatter = new DecimalFormat("$#,###,###,###,###.00");
	XmlRaw xmlReport = null;
	XmlFact xmlFact;
	Document document = null;
	PdfWriter writer;
	PdfContentByte cb = null;
	//Fonts
    BaseFont baseFontNormal;
    BaseFont baseFontBold;
    Font.FontFamily fontFamily;
	Integer fontRgb[] = new Integer[3];
	Integer localFontRgb[] = new Integer[3];
	Integer totalPages=0;
	Image bgImage;
	

	AbstractData f;
	
	/*
	 * Constructores
	 */

	public FactPdfV3(AbstractData f, XmlFact xml, XmlRaw plantilla, String bg) throws myXmlParsingException, BadElementException, MalformedURLException, IOException {
		if (bg!=null && !bg.isEmpty())
			bgImage=Image.getInstance(bg);
		build(f,xml,plantilla);
	}

public void build(AbstractData f, XmlFact xml, XmlRaw plantilla) throws myXmlParsingException {
	try{
		//Obtenemos el xml generador de la factura
		this.f=f;
		xmlFact = xml;
		xmlReport = plantilla;
        
		prepare();
        buildDetail();

        
        totalPages=writer.getPageNumber();
        
        
		prepare();
		writer.setPageEvent(this);
		NodeList detail = xmlReport.getNodes("Detail");
		if (detail.getLength()==0)
			document.add(new Paragraph(" "));
        buildDetail();
        
		addMetaData(document);
		document.close();



	} catch (Exception e) {
		e.printStackTrace();
		cb.beginText();
		try {
			cb.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, "Cp1252", false), new Integer(7));
		} catch (DocumentException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		ColumnText ct = new ColumnText(cb);
	    StringWriter sw = new StringWriter();
	    PrintWriter pw = new PrintWriter(sw);
	    e.printStackTrace(pw);
	    Phrase myText = new Phrase(sw.toString(), new Font(Font.FontFamily.HELVETICA, 7, Font.NORMAL));
	    ct.setSimpleColumn(myText, 1, 1, 700, 700, 10, Element.ALIGN_LEFT);
        try {
			ct.go();
		} catch (DocumentException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
        cb.endText();
		document.close();
	}
}


	private void prepare() throws DocumentException, IOException{
		//Tamaño de documento y detalle
		dataArray = new ByteArrayOutputStream();
				NodeList detail = xmlReport.getNodes("Detail");
				if (detail.getLength()>0)
					document = new Document(PageSize.LETTER, new Float(xmlReport.get("marginLeft")), new Float(xmlReport.get("marginRight")), 
							new Float(xmlReport.get("marginTop")), new Float(xmlReport.get("marginBottom")));
				else
					document = new Document();
				
				
				//Inicializacion
				writer = PdfWriter.getInstance(document,dataArray);
				document.open();
				cb = writer.getDirectContent();


		        
				/*
				 * Fonts
				 */
				if (xmlReport.get("font")!=null){
					if (xmlReport.get("font").equals("helvetica")){
						baseFontNormal = BaseFont.createFont(BaseFont.HELVETICA, "Cp1252", false);
			        	baseFontBold = BaseFont.createFont(BaseFont.HELVETICA_BOLD, "Cp1252", false);
			        	fontFamily = Font.FontFamily.HELVETICA;
					}else if (xmlReport.get("font").equals("times")){
						baseFontNormal = BaseFont.createFont(BaseFont.TIMES_ROMAN, "Cp1252", false);
			        	baseFontBold = BaseFont.createFont(BaseFont.TIMES_BOLD, "Cp1252", false);
			        	fontFamily = Font.FontFamily.TIMES_ROMAN;
					}else if (xmlReport.get("font").equals("courier")){
						baseFontNormal = BaseFont.createFont(BaseFont.COURIER, "Cp1252", false);
			        	baseFontBold = BaseFont.createFont(BaseFont.COURIER_BOLD, "Cp1252", false);
			        	fontFamily = Font.FontFamily.COURIER;
					}else{
						baseFontNormal = BaseFont.createFont(BaseFont.TIMES_ROMAN, "Cp1252", false);
			        	baseFontBold = BaseFont.createFont(BaseFont.TIMES_BOLD, "Cp1252", false);
			        	fontFamily = Font.FontFamily.TIMES_ROMAN;
					}
				}else{
					baseFontNormal = BaseFont.createFont(BaseFont.TIMES_ROMAN, "Cp1252", false);
		        	baseFontBold = BaseFont.createFont(BaseFont.TIMES_BOLD, "Cp1252", false);
		        	fontFamily = Font.FontFamily.TIMES_ROMAN;
				}
				
				//FontColor
				if (xmlReport.get("fontRgb")!=null && !xmlReport.get("fontRgb").isEmpty()){
					fontRgb[0]= new Integer(xmlReport.get("fontRgb").split(",")[0]);
					fontRgb[1]= new Integer(xmlReport.get("fontRgb").split(",")[1]);
					fontRgb[2]= new Integer(xmlReport.get("fontRgb").split(",")[2]);
				}else{
					fontRgb[0]=0;
					fontRgb[1]=0;
					fontRgb[2]=0;
				}
	}


	private void buildDetail() throws DocumentException{
        /*
         * Detail
         */
		NodeList detail;
        detail = xmlReport.getNodes("Detail");
        Font font = new Font(fontFamily, 8, Font.NORMAL);
        Font fontHeaders = new Font(fontFamily, 9, Font.BOLD);
    	font.setColor(fontRgb[0], fontRgb[1], fontRgb[2]);
    	fontHeaders.setColor(fontRgb[0], fontRgb[1], fontRgb[2]);
	        for (int x=0;x<detail.getLength();x++){
	        	String colWidths="";
	        	Node tableNode = detail.item(x);
	        	org.w3c.dom.Element tableElement = (org.w3c.dom.Element)tableNode;
	        	NodeList parts = tableElement.getElementsByTagName("Column");
	        	PdfPTable table = new PdfPTable(parts.getLength());
	        	//Headers
	        	for (int y=0;y<parts.getLength();y++){
	        		org.w3c.dom.Element e = (org.w3c.dom.Element)parts.item(y);
	        		PdfPCell c = new PdfPCell(new Phrase(e.getAttribute("name"),fontHeaders));
	        		c.setHorizontalAlignment(new Integer(e.getAttribute("align")));
	        		c.setBorder(0);
	        		if (e.getAttribute("height") != null && !e.getAttribute("height").isEmpty())
	        			c.setFixedHeight(new Integer(e.getAttribute("height")));
	        		table.addCell(c);
	        		colWidths+=e.getAttribute("width")+",";
	        	}
	        	//Detail
	        	NodeList partidas = xmlFact.getNodes(tableElement.getAttribute("source"));
		        	for (int z=0;z<partidas.getLength();z++){
		        		org.w3c.dom.Element partida = (org.w3c.dom.Element)partidas.item(z);
		            	for (int y=0;y<parts.getLength();y++){
		            		org.w3c.dom.Element e = (org.w3c.dom.Element)parts.item(y);
		            		PdfPCell c=null;
		            		if (!e.getAttribute("type").equals("Number"))
		            			c = new PdfPCell(new Phrase((partida.getAttribute(e.getAttribute("attribute"))==null?"":partida.getAttribute(e.getAttribute("attribute"))),font));
		            		else//En los numeros la cadena vacia genera error
		            			if (!partida.getAttribute(e.getAttribute("attribute")).isEmpty())
		            				c = new PdfPCell(new Phrase(formatter.format(new Double(partida.getAttribute(e.getAttribute("attribute")))),font));
		            		if (c!=null){
			            		c.setHorizontalAlignment(new Integer(e.getAttribute("align")));
			            		c.setBorder(0);
			            		table.addCell(c);
		            		}
		            	}
		        	}
		        table.setHeaderRows(1);
	            table.setTotalWidth(new Float(tableElement.getAttribute("totalWidth")));
	            table.setWidthPercentage(100);
	            float[] widths = new float[colWidths.split(",").length];
	            int cont=0;
	            for (String width : colWidths.split(",")){
	            	widths[cont] = new Float(width);
	            	cont++;
	            }
	            table.setWidths(widths);
	            table.setSplitLate(false);
	            document.add(table);
	        }
	}



	//Todo lo obligatorio por pagina, fondo, cavecera, pie, etc...
	@Override
	public void onEndPage (PdfWriter writer, Document document) {
		try{
			/*
			 * Imagen de fondo
			 */
		    //cargamos la plantilla de fondo
			if (bgImage!=null){
				bgImage.setAbsolutePosition(1, 1);
				document.add(bgImage);
			}
			
			
			
			/*
			 * Imagenes
			 */
	        NodeList images = xmlReport.getNodes("Image");
	        for (int x=0;x<images.getLength();x++){
	        	org.w3c.dom.Element e = (org.w3c.dom.Element)images.item(x);
			    Image img=null;
	        	//Imagen de archivo??
	        	if (e.getAttribute("file")!=null && !e.getAttribute("file").isEmpty()){
					try {
						img = Image.getInstance(e.getAttribute("file"));
					} catch (MalformedURLException e1) {
						continue;
					} catch (IOException e1) {
						continue;
					}
	        	}

				if (img==null)
					continue;
				if (e.getAttribute("scale")!=null)
					img.scalePercent(new Float(e.getAttribute("scale")));
				
				Float llx,lly,urx,ury,xPos,yPos;
				xPos = llx = new Float(e.getAttribute("llx"));
				yPos = lly = new Float(e.getAttribute("lly"));
				urx = new Float(e.getAttribute("urx"));
				ury = new Float(e.getAttribute("ury"));
				
				//stretch?
				if (e.getAttribute("stretch")!=null && e.getAttribute("stretch").equals("true")){
					float imgWidth=urx-llx, imgHeight=ury-lly;			
					if(img.getScaledHeight()>imgHeight)
						img.scaleAbsoluteHeight(imgHeight);
					else
						yPos+=((imgHeight-img.getScaledHeight())/2);
					if (img.getScaledWidth()>imgWidth)
						img.scaleAbsoluteWidth(imgWidth);
					else
						xPos+=((imgWidth-img.getScaledWidth())/2);
				}
				img.setAbsolutePosition(xPos, yPos);
		        document.add(img);
	        }
	        
	        
	        
	        
	        
	        cb.beginText();
	        
	        //Parsing XML Labels
	        NodeList labels = xmlReport.getNodes("Label");
	        for (int x=0;x<labels.getLength();x++){
	        	org.w3c.dom.Element e = (org.w3c.dom.Element)labels.item(x);
	        	if (e.getAttribute("bold")!=null && e.getAttribute("bold").equals("true"))
	        		cb.setFontAndSize(baseFontBold, new Integer(e.getAttribute("size")));
	        	else
	        		cb.setFontAndSize(baseFontNormal, new Integer(e.getAttribute("size")));
	        	//FontColor
	    		if (e.getAttribute("fontRgb")!=null && !e.getAttribute("fontRgb").isEmpty()){
	    			localFontRgb[0]= new Integer(e.getAttribute("fontRgb").split(",")[0]);
	    			localFontRgb[1]= new Integer(e.getAttribute("fontRgb").split(",")[1]);
	    			localFontRgb[2]= new Integer(e.getAttribute("fontRgb").split(",")[2]);
	    			cb.setRGBColorFill(localFontRgb[0], localFontRgb[1], localFontRgb[2]);
	    		}else{
	    			cb.setRGBColorFill(fontRgb[0], fontRgb[1], fontRgb[2]);
	    		}
	        	int align =  new Integer(e.getAttribute("align"));
	        	int xPos =  new Integer(e.getAttribute("xPos"));
	        	int yPos =  new Integer(e.getAttribute("yPos"));
	        	cb.showTextAligned(align, e.getAttribute("text"), xPos, yPos, 0);
	        }
	        
	        
	        
	        
	        
	        //Parsing XML Text
	        NodeList texts = xmlReport.getNodes("Text");
	        String finalData="";
	        for (int x=0;x<texts.getLength();x++){
	        	org.w3c.dom.Element e = (org.w3c.dom.Element)texts.item(x);
	        	if (e.getAttribute("bold")!=null && e.getAttribute("bold").equals("true"))
	        		cb.setFontAndSize(baseFontBold, new Integer(e.getAttribute("size")));
	        	else
	        		cb.setFontAndSize(baseFontNormal, new Integer(e.getAttribute("size")));
	        	//FontColor
	    		if (e.getAttribute("fontRgb")!=null && !e.getAttribute("fontRgb").isEmpty()){
	    			localFontRgb[0]= new Integer(e.getAttribute("fontRgb").split(",")[0]);
	    			localFontRgb[1]= new Integer(e.getAttribute("fontRgb").split(",")[1]);
	    			localFontRgb[2]= new Integer(e.getAttribute("fontRgb").split(",")[2]);
	    			cb.setRGBColorFill(localFontRgb[0], localFontRgb[1], localFontRgb[2]);
	    		}else{
	    			cb.setRGBColorFill(fontRgb[0], fontRgb[1], fontRgb[2]);
	    		}
	        	int align =  new Integer(e.getAttribute("align"));
	        	int xPos =  new Integer(e.getAttribute("xPos"));
	        	int yPos =  new Integer(e.getAttribute("yPos"));
	        	finalData = parse(e.getAttribute("source"),e.getAttribute("type"),
	        			e.getAttribute("mask"),xmlFact,f);
	        	cb.showTextAligned(align, finalData, xPos, yPos, 0);
	        }
	        
	        
	        
	        
	        //Parsing XML Box's
	        NodeList boxs = xmlReport.getNodes("Box");
	    	Font font;
	        for (int x=0;x<boxs.getLength();x++){
	        	org.w3c.dom.Element e = (org.w3c.dom.Element)boxs.item(x);
	        	if (e.getAttribute("bold")!=null && e.getAttribute("bold").equals("true"))
	        		font = new Font(fontFamily, new Float(e.getAttribute("size")), Font.BOLD);
	        	else
	        		font = new Font(fontFamily, new Float(e.getAttribute("size")), Font.NORMAL);

	        	//FontColor
	    		if (e.getAttribute("fontRgb")!=null && !e.getAttribute("fontRgb").isEmpty()){
	    			localFontRgb[0]= new Integer(e.getAttribute("fontRgb").split(",")[0]);
	    			localFontRgb[1]= new Integer(e.getAttribute("fontRgb").split(",")[1]);
	    			localFontRgb[2]= new Integer(e.getAttribute("fontRgb").split(",")[2]);
	    			font.setColor(localFontRgb[0], localFontRgb[1], localFontRgb[2]);
	    		}else{
	    			font.setColor(fontRgb[0], fontRgb[1], fontRgb[2]);
	    		}
	    		
		        ColumnText ct = new ColumnText(cb);
	        	finalData = parse(e.getAttribute("source"),e.getAttribute("type"),
	        			e.getAttribute("mask"),xmlFact,f);
		        Phrase myText = new Phrase(finalData, font);
		        ct.setSimpleColumn(myText, new Float(e.getAttribute("llx")), 
		        		new Float(e.getAttribute("lly")), 
		        		new Float(e.getAttribute("urx")), 
		        		new Float(e.getAttribute("ury")), 
		        		new Float(e.getAttribute("leading")), new Integer(e.getAttribute("align")));
		        ct.go();
	        }
	        
	        
	        
	        //Paginacion
	        cb.showTextAligned(0, "Pagina: " + writer.getPageNumber() + " de: " + totalPages, 25, 12, 0);
	        cb.endText();

	        
	        
	        
	        
	        /*
	         * Tablas
	         */
	        NodeList tables = xmlReport.getNodes("Table");
	        font = new Font(fontFamily, 8, Font.NORMAL);
	    	Font fontHeaders = new Font(fontFamily, 9, Font.BOLD);
	    	font.setColor(fontRgb[0], fontRgb[1], fontRgb[2]);
	    	fontHeaders.setColor(fontRgb[0], fontRgb[1], fontRgb[2]);
		        for (int x=0;x<tables.getLength();x++){
		        	String colWidths="";
		        	Node tableNode = tables.item(x);
		        	org.w3c.dom.Element tableElement = (org.w3c.dom.Element)tableNode;
		        	NodeList parts = tableElement.getElementsByTagName("Column");
		        	PdfPTable table = new PdfPTable(parts.getLength());
		        	//Headers
		        	for (int y=0;y<parts.getLength();y++){
		        		org.w3c.dom.Element e = (org.w3c.dom.Element)parts.item(y);
		        		PdfPCell c = new PdfPCell(new Phrase(e.getAttribute("name"),fontHeaders));
		        		c.setHorizontalAlignment(new Integer(e.getAttribute("align")));
		        		c.setBorder(0);
		        		if (e.getAttribute("height") != null && !e.getAttribute("height").isEmpty())
		        			c.setFixedHeight(new Integer(e.getAttribute("height")));
		        		table.addCell(c);
		        		colWidths+=e.getAttribute("width")+",";
		        	}
		        	//Detail
		        	NodeList partidas = xmlFact.getNodes(tableElement.getAttribute("source"));
			        	for (int z=0;z<partidas.getLength();z++){
			        		org.w3c.dom.Element partida = (org.w3c.dom.Element)partidas.item(z);
			            	for (int y=0;y<parts.getLength();y++){
			            		org.w3c.dom.Element e = (org.w3c.dom.Element)parts.item(y);
			            		PdfPCell c=null;
			            		if (!e.getAttribute("type").equals("Number"))
			            			c = new PdfPCell(new Phrase((partida.getAttribute(e.getAttribute("attribute"))==null?"":partida.getAttribute(e.getAttribute("attribute"))),font));
			            		else//En los numeros la cadena vacia genera error
			            			if (!partida.getAttribute(e.getAttribute("attribute")).isEmpty())
			            				c = new PdfPCell(new Phrase(formatter.format(new Double(partida.getAttribute(e.getAttribute("attribute")))),font));
			            		if (c!=null){
				            		c.setHorizontalAlignment(new Integer(e.getAttribute("align")));
				            		c.setBorder(0);
				            		table.addCell(c);
			            		}
			            	}        		
			        	}
		            table.setTotalWidth(new Float(tableElement.getAttribute("totalWidth")));
		            float[] widths = new float[colWidths.split(",").length];
		            int cont=0;
		            for (String width : colWidths.split(",")){
		            	widths[cont] = new Float(width);
		            	cont++;
		            }
		            table.setWidths(widths);
		    	    table.writeSelectedRows(0, -1, new Float(tableElement.getAttribute("xPos")), new Float(tableElement.getAttribute("yPos")), writer.getDirectContent()); 
		        }
		        
		        
		        
				
				
				//QR Code
				if (xmlFact.get("version").startsWith("3")){
					NumberFormat qrformatter = new DecimalFormat("0000000000.000000");
					Image qrCode = generateQRCodeImage("?re="+xmlFact.getAttrib("Emisor", "rfc")+"&rr="+xmlFact.getAttrib("Receptor", "rfc")+"&tt="+qrformatter.format(new Double(xmlFact.getAttrib(null, "total")))+"&id="+xmlFact.getAttrib("Complemento/tfd:TimbreFiscalDigital", "UUID"),140,140);
					NodeList detail = xmlReport.getNodes("Detail");
					if (detail.getLength()>0)
						qrCode.setAbsolutePosition(460, 15);
					else
						qrCode.setAbsolutePosition(438, 20);
					document.add(qrCode);
				}
		        
		        
		} catch (Exception e) {
			e.printStackTrace();
	//		cb.beginText();
			try {
				cb.setFontAndSize(BaseFont.createFont(BaseFont.HELVETICA, "Cp1252", false), new Integer(7));
			} catch (DocumentException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			ColumnText ct = new ColumnText(cb);
		    StringWriter sw = new StringWriter();
		    PrintWriter pw = new PrintWriter(sw);
		    e.printStackTrace(pw);
		    Phrase myText = new Phrase(sw.toString(), new Font(Font.FontFamily.HELVETICA, 7, Font.NORMAL));
		    ct.setSimpleColumn(myText, 1, 1, 700, 700, 10, Element.ALIGN_LEFT);
	        try {
				ct.go();
			} catch (DocumentException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        cb.endText();
			document.close();
		}
	}

	// iText allows to add metadata to the PDF which can be viewed in your Adobe
	// Reader
	// under File -> Properties
	private  void addMetaData(Document document) {
		document.addTitle("Comprobante Fiscal Digital por Internet");
		document.addSubject("CFDI");
		document.addKeywords("e--fact, CFDI, LizBet, LizBetSoft");
		document.addAuthor("Alberto Sandoval Sotelo");
		document.addCreator("www.lizbetsoft.com");
	}


	/*
	 * Generacion de Imagen QR
	 */
	private Image generateQRCodeImage(String code, int width, int height) throws Exception { 
	    if (code == null || code.length() == 0) 
	            throw new Exception("Code unspecified"); 
	    if (width <= 0 || height <= 0) 
	            throw new Exception("Invalid width: " + width + " or height " + height); 
	    if (width != height) 
	            throw new Exception("width " + width + " and height " + height + " are not the same"); 
	    QRCode qrcode = new QRCode(); 
	    Encoder.encode(code, ErrorCorrectionLevel.L, qrcode); 
	    int qrSize = qrcode.getMatrixWidth(); 
	    int margin = 4; 
	    int imageSize = qrSize + 2 * margin; // includes quiet zone 
	    if (width < imageSize) width = imageSize; 
	    int magnify = width / imageSize; 
	    int remaining = width % imageSize; 
	    int topLeftPosition =  ((remaining > 0) ? remaining / 2 : magnify) + margin * magnify; 
	    int size = width; 

	    byte[] rawData = new byte[size*size];
	    for (int x=0;x<size*size;x++)
	    	rawData[x]=(byte) 255;
	    
	    for (int i = 0; i < qrSize; i ++) { 
            for (int j = 0; j < qrSize; j ++) { 
                    if (qrcode.at(i, j) == 1){
                            fillRect(rawData,topLeftPosition + i * magnify, topLeftPosition + j * magnify, magnify, magnify, size);
                    }
            } 
	    } 
	    Image img = new ImgRaw(size,size,1,8,rawData);
	    return img;
	} 

	//Emulacion de funcion grafica no disponible en el APP Engine
	private void fillRect(byte[] data, int xin,int yin,int xlenin,int ylenin, int size){
		int x=xin+1, y=yin+1, xlen=xlenin-1, ylen=ylenin-1; //Ajuste para dejar todo mas delgado
		int xRawStart=(y*size)+x, xRawEnd=(y*size)+x+xlen;
		for (int ycount=0;ycount<=ylen;ycount++){
			for (int cont=xRawStart;cont<=xRawEnd;cont++)
				data[cont]=(byte) 0;
			xRawStart+=size;
			xRawEnd+=size;
		}
	}
	
	
	//Parsea datos
	private String parse(String path, String type, String mask, XmlRaw xmlFact, AbstractData f){
		String data;
		if (path.equals("importeConLetra"))
			if (f.getAbstractData("moneda")!=null)
				return NumberToLetterConverter.Num2Text(new Double(xmlFact.get("total")),f.getAbstractData("moneda"));
			else
				return NumberToLetterConverter.Num2Text(new Double(xmlFact.get("total")),xmlFact.get("Moneda"));
		else if (path.equals("cadenaTimbre"))
			return ((XmlFact)xmlFact).getCadenaTimbre();
		else if (path.equals("cadenaCfd"))
			return ((XmlFact)xmlFact).getCadenaOriginal();
		
		
   		try {
	       if (LbsParser.parse(path, xmlFact, f) != null)
	         data = LbsParser.parse(path, xmlFact, f).toString();
	       else
	        data = "";
		} catch (LbsParserException e1) {
			return "Error#";
		}
 
    	//Si no se espesifica tipo de datos, por default es String
    	if (type==null)
    		return data==null?"":data;
    	else if (type.equals("Number") && data !=null ){
        	if (mask.isEmpty())
        		mask="###,###,###,###,###.00";
    		NumberFormat format = new DecimalFormat(mask);
    		if (data instanceof String && !data.isEmpty())
    			return format.format(new Double(data));
    		else
    			try{
    				return format.format(data.toString());
    			}catch (Exception ex){
    				return "Error#";
    			}
    	}else if (type.equals("Date") && data!=null){
    		SimpleDateFormat dformat;
            dformat = (SimpleDateFormat)DateFormat.getDateInstance();
            dformat.setTimeZone(TimeZone.getTimeZone("America/Mexico_City"));
        	if (mask.isEmpty())
        		mask="dd-MM-yyyy hh:mm:ss a";
       		dformat.applyPattern(mask);
			try{
				return dformat.format(new Date(data));
			}catch (Exception ex){
				ex.printStackTrace();
				return "Error#";
			}
    	}else if (data==null || data.equals("null"))
			return "";
    	else //Desconocidos String
    		return  (data==null?"":data).toString();
	}
	
	
	
}